home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / sound / muzika.zip / MUZSRC1.ZIP / FORMAT.CPP < prev    next >
C/C++ Source or Header  |  1992-07-22  |  7KB  |  174 lines

  1. // **********************************************
  2. // File: FORMAT.CPP
  3. // Musical text formatting functions
  4.  
  5. #include "muzika.h"
  6. #include <alloc.h>
  7. #include <values.h>
  8.  
  9. // **********************************************
  10. // FindMinDuration finds the minimum in a list and
  11. // returns its index. This function is used to find
  12. // the minimum duration of the next object among several staves.
  13.  
  14. int FindMinDuration(int *duration, int multiplicity)
  15. {
  16.   int min = MAXINT, minIndex;
  17.   int *p = duration;
  18.  
  19.   while (multiplicity--) {
  20.     if (min > *p) {
  21.       min = *p;
  22.       minIndex = p-duration;
  23.     }
  24.     ++p;
  25.   }
  26.  
  27.   return minIndex;
  28. }
  29.  
  30. // **********************************************
  31. // FormatMultipleStaff reformats a multiple staff.
  32. // This function is called once for every multiple staff in the part.
  33.  
  34. void FormatMultipleStaff(int baseStaff)
  35. {
  36.   // Create a few lists for use in the algorithm
  37.   Part &p = *((Part *) &melody.part[displayedPart]);
  38.   int *duration = (int *) malloc(p.multiplicity()*sizeof(int));
  39.   int *index = (int *) malloc(p.multiplicity()*sizeof(int));
  40.   BOOL *atCommon = (int *) malloc(p.multiplicity()*sizeof(BOOL));
  41.   BOOL *staffEnd = (int *) malloc(p.multiplicity()*sizeof(BOOL));
  42.   memset(duration, 0, p.multiplicity()*sizeof(int));
  43.   memset(index, 0, p.multiplicity()*sizeof(int));
  44.   memset(atCommon, 0, p.multiplicity()*sizeof(BOOL));
  45.   memset(staffEnd, 0, p.multiplicity()*sizeof(BOOL));
  46.   int X = 0;
  47.   BOOL multipleEnd, multipleReached = FALSE;
  48.  
  49.   // Create unions of the continuousObject lists sorted by Xleft and Xright
  50.   IndexedList sortedByLeft, sortedByRight;
  51.   int leftIndex, rightIndex;
  52.   for (int staffIndex = 0; staffIndex < p.multiplicity(); ++staffIndex) {
  53.     Staff &s = *((Staff *) &p.staff[baseStaff+staffIndex]);
  54.     for (int orgIndex = 0; orgIndex < s.continuousObject.number(); ++orgIndex) {
  55.       for (leftIndex = 0;
  56.         leftIndex < sortedByLeft.number() &&
  57.           ((ContinuousObject *) &sortedByLeft[leftIndex])->Xleft() <=
  58.           ((ContinuousObject *) &s.continuousObject[orgIndex])->Xleft();
  59.         ++leftIndex);
  60.       sortedByLeft.insertAt(s.continuousObject[orgIndex], leftIndex);
  61.       for (rightIndex = 0;
  62.         rightIndex < sortedByRight.number() &&
  63.           ((ContinuousObject *) &sortedByRight[rightIndex])->Xright() <=
  64.           ((ContinuousObject *) &s.continuousObject[orgIndex])->Xright();
  65.         ++rightIndex);
  66.       sortedByRight.insertAt(s.continuousObject[orgIndex], rightIndex);
  67.     }
  68.   }
  69.  
  70.   // Loop as long as the end has not been reached on all staves
  71.   do {
  72.     // Find the staff with the minimum duration of the next object
  73.     int minIndex = FindMinDuration(duration, p.multiplicity());
  74.     int minDuration = duration[minIndex];
  75.     int maxWidth = 0;
  76.     multipleEnd = TRUE;
  77.  
  78.     // Subtract the minimum duration from all staves;
  79.     // place the next object on the ones which reach 0 as a result
  80.     for (staffIndex = 0; staffIndex < p.multiplicity(); ++staffIndex) {
  81.       Staff &s = *((Staff *) &p.staff[baseStaff+staffIndex]);
  82.  
  83.       if (atCommon[staffIndex] || !(duration[staffIndex] -= minDuration)) {
  84.         // The next object duration has reached 0:
  85.         // place the next object in the staff
  86.         int currX = ((PointObject *) &s.pointObject[index[staffIndex]])->X();
  87.         while (!(staffEnd[staffIndex] =
  88.           index[staffIndex] == s.pointObject.number())) {
  89.           PointObject &obj =
  90.             *((PointObject *) &s.pointObject[index[staffIndex]]);
  91.           if (obj.X() == currX) {
  92.             if ((obj.location() & ~ONEPERSTAFF) == COMMONMULTIPLE) {
  93.               // The object has a COMMONMULTIPLE location attribute:
  94.               // mark the place and wait for other staves to reach
  95.               // this object too
  96.               atCommon[staffIndex] = !multipleReached;
  97.               duration[staffIndex] = multipleReached ? 0 : MAXINT;
  98.               if (!multipleReached)
  99.                 break;
  100.             }
  101.  
  102.             // Reinitialize the next object duration
  103.             if (duration[staffIndex] < obj.Duration())
  104.               duration[staffIndex] = obj.Duration();
  105.  
  106.             // Call the object's Format virtual function,
  107.             // in case the object wants to do something during formatting
  108.             obj.Format(X);
  109.             if (maxWidth < obj.Width())
  110.               maxWidth = obj.Width();
  111.             ++index[staffIndex];
  112.  
  113.             // Adjust the left and right coordinates
  114.             // of any continuous objects that have been reached
  115.             // while reformatting the point objects
  116.             while (leftIndex < sortedByLeft.number() &&
  117.               ((ContinuousObject *)
  118.                 &sortedByLeft[leftIndex])->Xleft() <= currX)
  119.               ((ContinuousObject *)
  120.                 &sortedByLeft[leftIndex++])->FormatLeft(X);
  121.             while (rightIndex < sortedByRight.number() &&
  122.               ((ContinuousObject *)
  123.                 &sortedByRight[rightIndex])->Xright() <= currX)
  124.               ((ContinuousObject *)
  125.                 &sortedByRight[rightIndex++])->FormatRight(X);
  126.           }
  127.           else break;
  128.         }
  129.       }
  130.  
  131.       // See if the end has been reached on all staves
  132.       multipleEnd = multipleEnd && staffEnd[staffIndex];
  133.     }
  134.  
  135.     // See if an object with a COMMONMULTIPLE location attribute
  136.     // has been reached on all staves
  137.     multipleReached = TRUE;
  138.     for (staffIndex = 0; staffIndex < p.multiplicity(); ++staffIndex)
  139.       multipleReached = multipleReached && atCommon[staffIndex];
  140.  
  141.     X += maxWidth;
  142.   } while (!multipleEnd);
  143.  
  144.   // Free the continuous object list copies
  145.   for (int i = sortedByLeft.number()-1; i >= 0; --i) {
  146.     sortedByLeft.detachAt(i);
  147.     sortedByRight.detachAt(i);
  148.   }
  149.  
  150.   // Free all temporary lists on the heap
  151.   free(staffEnd);
  152.   free(atCommon);
  153.   free(index);
  154.   free(duration);
  155. }
  156.  
  157. // **********************************************
  158. // FormatEntirePart reformats the displayed part
  159. // by calling FormatMultipleStaff once per every multiple staff
  160. // in the part.
  161.  
  162. void FormatEntirePart()
  163. {
  164.   Part &p = *((Part *) &melody.part[displayedPart]);
  165.  
  166.   // Call FormatMultipleStaff for every multiple staff in the part
  167.   for (int index = 0; index < p.staff.number(); index += p.multiplicity())
  168.     FormatMultipleStaff(index);
  169.  
  170.   // Mark the melody as modified and refresh screen
  171.   melodyModified = TRUE;
  172.   InvalidateRect(hEditWnd, NULL, TRUE);
  173. }
  174.